package KUtilities;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;

public class KTextField extends JTextField {
	private static final long serialVersionUID = 1L;
	private JPopupMenu autoPopup;
	private JList autoList;
	private JScrollPane autoScroll;
	private DefaultListModel autoComplete;
	private Map<String,String> autoMap;
	private String autoSeperator=" ",keyValueSeperator=" - ";
	private boolean show,enabled,searchValue=true;
	
	public KTextField() {
	}

	public KTextField(String arg0) {
		super(arg0);
	}

	public KTextField(int arg0) {
		super(arg0);
	}

	public KTextField(String arg0, int arg1) {
		super(arg0, arg1);
	}

	public KTextField(Document arg0, String arg1, int arg2) {
		super(arg0, arg1, arg2);
	}

	public void setOpaque(boolean opaque){
		super.setOpaque(opaque);
		if(autoPopup!=null)
			autoPopup.setOpaque(opaque);
		if(autoList!=null)
			autoList.setOpaque(opaque);
		if(autoScroll!=null)
			autoScroll.setOpaque(opaque);
	}

	/**
	 * Enables auto Complete
	 */
	public void enableAutoComplete(){
		if(!enabled){
			if(autoMap==null)
				autoMap=new HashMap<String,String>();
			autoPopup=new JPopupMenu();
			autoComplete=new DefaultListModel();
			autoList=new JList(autoComplete);
			autoScroll=new JScrollPane(autoList);
			
			autoPopup.add(autoScroll);
			
			autoList.setFocusable(false);
			autoScroll.setBorder(null);
			autoPopup.setBorder(BorderFactory.createRaisedBevelBorder()); 
			setOpaque(isOpaque());
			getDocument().addDocumentListener(new DocumentListener(){
				public void changedUpdate(DocumentEvent arg0) {
				}
				public void insertUpdate(DocumentEvent arg0) {
					showPopup();
				}
				private void showPopup() {
		            autoComplete.removeAllElements();
		            Iterator<String> iterator=autoMap.keySet().iterator();
		            while(iterator.hasNext()){
		            	String key=iterator.next();
		            	String text=getText().toLowerCase();
		            	int index=text.lastIndexOf("\n");
		            	if(index!=-1)
		            		text=text.substring(index+1);
		            	index=text.lastIndexOf(autoSeperator);
		            	if(index!=-1)
		            		text=text.substring(index+1);
	            		if(show)
	            			key+=keyValueSeperator+autoMap.get(key);
		            	if(accept(key.toLowerCase(),text)){
		            		autoComplete.addElement(key);
		            	}
		            }
		            autoPopup.setVisible(false); 
			        if(KTextField.this.hasFocus() && isEnabled() && autoList.getModel().getSize()!=0){ 
			            int size = autoList.getModel().getSize(); 
			            autoList.setVisibleRowCount(size<5 ? size : 5); 
			            int x = 0; 
			            try{ 
			                int pos = Math.min(getCaret().getDot(), getCaret().getMark()); 
			                x = KTextField.this.getUI().modelToView(KTextField.this, pos).x; 
			            } catch(Exception e){ 
			                e.printStackTrace(); 
			            } 
			            autoPopup.show(KTextField.this, x, KTextField.this.getHeight()); 
			        }else 
			        	autoPopup.setVisible(false); 
			        requestFocus(); 
				}
				public void removeUpdate(DocumentEvent arg0) {
					showPopup();
				}
			});
			
			Action enterAction=new AbstractAction(){
				private static final long serialVersionUID = 1L;
				public void actionPerformed(ActionEvent arg0) {
					int index=autoList.getSelectedIndex();
					if(autoPopup.isVisible()&&index!=-1){
						String text=getText();
						String value=getAutoCompleteValue(autoList.getSelectedValue().toString());
						index=text.lastIndexOf(autoSeperator);
	            		text=text.substring(index+1);
		            	if(Character.isUpperCase(text.charAt(0)))
		            		value=value.substring(0,1).toUpperCase()+value.substring(1);
		            	text=getText().substring(0,index+1);
		            	setText(text+value+autoSeperator);
		            	//KTextArea.this.replaceRange(value+autoSeperator, index+1, index+1+text.length());
					}
					autoPopup.setVisible(false);
				}
			};
			
			Action upAction=new AbstractAction(){
				private static final long serialVersionUID = 1L;
				public void actionPerformed(ActionEvent arg0) {
					int index=autoList.getSelectedIndex();
					if(autoPopup.isVisible()){
						if(index==0)
							index=autoComplete.getSize();
						autoList.setSelectedIndex(index-1);
						autoList.ensureIndexIsVisible(index-1);
					}
				}
			};
			
			Action downAction=new AbstractAction(){
				private static final long serialVersionUID = 1L;
				public void actionPerformed(ActionEvent arg0) {
					int index=autoList.getSelectedIndex();
					if(autoPopup.isVisible()){
						if(index==autoComplete.getSize()-1)
							index=-1;
						autoList.setSelectedIndex(index+1);
						autoList.ensureIndexIsVisible(index+1);
					}
				}
			};
			registerKeyboardAction(enterAction,KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),JComponent.WHEN_FOCUSED);
			registerKeyboardAction(upAction,KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),JComponent.WHEN_FOCUSED);
			registerKeyboardAction(downAction,KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),JComponent.WHEN_FOCUSED);
			enabled=true;
		}
	}
	
	/**
	 * Disable Auto Complete
	 */
	public void disableAutoComplete(){
		if(enabled){
			autoPopup=null;
			autoComplete=null;
			autoList=null;
			autoScroll=null;
			unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
			unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0));
			unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0));
			enabled=false;
		}
	}
	
	/**
	 * Enables auto Complete
	 * @param map map of possible items
	 */
	public void enableAutoComplete(Map<String,String> map){
		enableAutoComplete(map,false);
	}
	
	/**
	 * Enables Auto Complete
	 * @param map map of possible items
	 * @param show Show key - value in popup
	 */
	public void enableAutoComplete(Map<String,String> map,boolean show){
		autoMap=map;
		this.show=show;
		enableAutoComplete();
	}
	
	/**
	 * Set the seperator string.. Default is space 
	 * @param sep string used to seperate
	 */
	public void setAutoCompleteSeperator(String sep){
		autoSeperator=sep;
	}
	
	/**
	 * Set the seperator string between key value pair.. Default is " - " 
	 * @param sep string used to seperate
	 */
	public void setKeyValueSeperator(String sep){
		keyValueSeperator=sep;
	}
	
	/**
	 * Set whether to search value while showing popup auto complete list, true by default
	 * @param search do u want to search in value also
	 */
	public void searchInvalue(boolean search){
		searchValue=search;
	}
	
	/**
	 * Accept this item to add to autoComplete popup or not
	 * @param inList item from list
	 * @param typedText the text Typed in TextField
	 * @return true if accepted, false otherwise
	 */
	public boolean accept(String listText,String typedText){
		if(searchValue&&show){
			String temp[]=listText.split(keyValueSeperator);
			if(temp[0].startsWith(typedText)||temp[1].startsWith(typedText)&&!temp[1].equals(typedText))
				return true;
		}else{
			if(listText.startsWith(typedText))
				return true;
		}
		return false;
	}
	
	/**
	 * Returns the value of the selected item from Auto Complete Popup..
	 * @param selectedFromAutoComplete value Selected from list
	 */
	public String getAutoCompleteValue(String selectedValue){
		if(!show)
			return autoMap.get(selectedValue);
		else{
			String temp[]=selectedValue.split(keyValueSeperator);
			return autoMap.get(temp[0]);
		}		
	}
}
